home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / jpegv3.zip / JDMAIN.C < prev    next >
Text File  |  1992-03-21  |  13KB  |  502 lines

  1. /*
  2.  * jdmain.c
  3.  *
  4.  * Copyright (C) 1991, 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains an MS-DOS user interface for the JPEG decompressor.
  9.  * It follows DOS practice more closely than does the standard jdmain.c.
  10.  * This compiles under Borland C or Microsoft C; don't know about others.
  11.  */
  12.  
  13. #include "jinclude.h"
  14. #include <stdlib.h>        /* to declare exit() */
  15. #include <string.h>        /* string functions */
  16. #include <signal.h>        /* to declare signal() */
  17.  
  18. #ifdef __TURBOC__
  19.                 /* Borland C declarations */
  20. #include <dir.h>        /* for findfirst/findnext */
  21. typedef struct ffblk FF_DATA;
  22. #define FF_NAME  ff_name
  23. #define FINDFIRST(path,blk)    findfirst(path, blk, 0)
  24. #define FINDNEXT(blk)        findnext(blk)
  25.  
  26. #else /* !__TURBOC__ */
  27.                 /* Microsoft C declarations */
  28. #include <dos.h>        /* for findfirst/findnext */
  29. typedef struct find_t FF_DATA;
  30. #define FF_NAME  name
  31. #define FINDFIRST(path,blk)    _dos_findfirst(path, _A_NORMAL, blk)
  32. #define FINDNEXT(blk)        _dos_findnext(blk)
  33.  
  34. #endif /* __TURBOC__ */
  35.  
  36. #define READ_BINARY    "rb"
  37. #define WRITE_BINARY    "wb"
  38.  
  39. #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
  40. #define EXIT_FAILURE  1
  41. #endif
  42. #ifndef EXIT_SUCCESS
  43. #define EXIT_SUCCESS  0
  44. #endif
  45.  
  46.  
  47. #include "jversion.h"        /* for version message */
  48.  
  49.  
  50. /*
  51.  * PD version of getopt(3).
  52.  */
  53.  
  54. #include "egetopt.c"
  55.  
  56.  
  57. /*
  58.  * This list defines the known output image formats
  59.  * (not all of which need be supported by a given version).
  60.  * You can change the default output format by defining DEFAULT_FMT;
  61.  * indeed, you had better do so if you undefine GIF_SUPPORTED.
  62.  */
  63.  
  64. typedef enum {
  65.     FMT_GIF,        /* GIF format */
  66.     FMT_PPM,        /* PPM/PGM (PBMPLUS formats) */
  67.     FMT_RLE,        /* RLE format */
  68.     FMT_TARGA,        /* Targa format */
  69.     FMT_TIFF        /* TIFF format */
  70. } IMAGE_FORMATS;
  71.  
  72. #ifndef DEFAULT_FMT        /* so can override from CFLAGS in Makefile */
  73. #define DEFAULT_FMT    FMT_GIF
  74. #endif
  75.  
  76. static IMAGE_FORMATS requested_fmt;
  77.  
  78.  
  79. /*
  80.  * This routine gets control after the input file header has been read.
  81.  * It must determine what output file format is to be written,
  82.  * and make any other decompression parameter changes that are desirable.
  83.  */
  84.  
  85. METHODDEF void
  86. d_ui_method_selection (decompress_info_ptr cinfo)
  87. {
  88.   /* if grayscale or CMYK input, force similar output; */
  89.   /* else leave the output colorspace as set by options. */
  90.   if (cinfo->jpeg_color_space == CS_GRAYSCALE)
  91.     cinfo->out_color_space = CS_GRAYSCALE;
  92.   else if (cinfo->jpeg_color_space == CS_CMYK)
  93.     cinfo->out_color_space = CS_CMYK;
  94.  
  95.   /* select output file format */
  96.   /* Note: jselwxxx routine may make additional parameter changes,
  97.    * such as forcing color quantization if it's a colormapped format.
  98.    */
  99.   switch (requested_fmt) {
  100. #ifdef GIF_SUPPORTED
  101.   case FMT_GIF:
  102.     jselwgif(cinfo);
  103.     break;
  104. #endif
  105. #ifdef PPM_SUPPORTED
  106.   case FMT_PPM:
  107.     jselwppm(cinfo);
  108.     break;
  109. #endif
  110. #ifdef RLE_SUPPORTED
  111.   case FMT_RLE:
  112.     jselwrle(cinfo);
  113.     break;
  114. #endif
  115. #ifdef TARGA_SUPPORTED
  116.   case FMT_TARGA:
  117.     jselwtarga(cinfo);
  118.     break;
  119. #endif
  120.   default:
  121.     ERREXIT(cinfo->emethods, "Unsupported output file format");
  122.     break;
  123.   }
  124. }
  125.  
  126.  
  127. /*
  128.  * Signal catcher to ensure that temporary files are removed before aborting.
  129.  * Doesn't do anything during intervals where emethods is NULL.
  130.  */
  131.  
  132. static external_methods_ptr emethods; /* for access to free_all */
  133.  
  134. LOCAL void
  135. signal_catcher (int signum)
  136. {
  137.   if (emethods != NULL) {
  138.     emethods->trace_level = 0;    /* turn off trace output */
  139.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  140.   }
  141.   exit(EXIT_FAILURE);
  142. }
  143.  
  144.  
  145. LOCAL void
  146. usage (void)
  147. /* complain about bad command line */
  148. {
  149.   fprintf(stderr, "Usage: djpeg [switches] inputfile(s)\n");
  150.   fprintf(stderr, "List of input files may use wildcards (* and ?)\n");
  151.   fprintf(stderr, "If input file name has no extension, .JPG is assumed\n");
  152.   fprintf(stderr, "Output filename is same as input filename, except for extension\n");
  153.   fprintf(stderr, "Optional switches:\n");
  154. #ifdef GIF_SUPPORTED
  155.   fprintf(stderr, "  -G          Select GIF output, extension .GIF  (default)\n");
  156. #endif
  157. #ifdef PPM_SUPPORTED
  158.   fprintf(stderr, "  -P          Select PPM/PGM output, extension .PPM\n");
  159. #endif
  160. #ifdef RLE_SUPPORTED
  161.   fprintf(stderr, "  -R          Select Utah RLE output, extension .RLE\n");
  162. #endif
  163. #ifdef TARGA_SUPPORTED
  164.   fprintf(stderr, "  -T          Select Targa output, extension .TGA\n");
  165. #endif
  166.   fprintf(stderr, "  -g          Force grayscale output\n");
  167.   fprintf(stderr, "  -q colors   Quantize to no more than N colors\n");
  168.   fprintf(stderr, "  -1          Use 1-pass quantization (fast, low quality)\n");
  169.   fprintf(stderr, "  -D          Don't use dithering in quantization\n");
  170.   fprintf(stderr, "  -b          Apply cross-block smoothing\n");
  171.   fprintf(stderr, "  -m memory   Maximum memory to use (default 300K); see USAGE\n");
  172.   fprintf(stderr, "  -d          Generate debug output\n");
  173.   exit(EXIT_FAILURE);
  174. }
  175.  
  176.  
  177. /* Display progress report */
  178.  
  179. METHODDEF void
  180. progress_monitor (decompress_info_ptr cinfo, long loopcounter, long looplimit)
  181. {
  182.   if (cinfo->total_passes > 1) {
  183.     fprintf(stderr, "\rPass %d/%d: %3d%% ",
  184.         cinfo->completed_passes+1, cinfo->total_passes,
  185.         (int) (loopcounter*100L/looplimit));
  186.   } else {
  187.     fprintf(stderr, "\r %3d%% ",
  188.         (int) (loopcounter*100L/looplimit));
  189.   }
  190.   fflush(stderr);
  191. }
  192.  
  193.  
  194. /*
  195.  * Check for overwrite of an existing file; clear it with user
  196.  */
  197.  
  198. LOCAL boolean
  199. is_write_ok (char * outfilename)
  200. {
  201.   FILE * ofile;
  202.   int ch;
  203.  
  204.   ofile = fopen(outfilename, READ_BINARY);
  205.   if (ofile == NULL)
  206.     return TRUE;        /* not present */
  207.   fclose(ofile);        /* oops, it is present */
  208.  
  209.   for (;;) {
  210.     fprintf(stderr, "%s already exists, overwrite it? [y/n] ",
  211.         outfilename);
  212.     fflush(stderr);
  213.     ch = getc(stdin);
  214.     fflush(stdin);        /* flush rest of line */
  215.     switch (ch) {
  216.     case 'Y':
  217.     case 'y':
  218.       return TRUE;
  219.     case 'N':
  220.     case 'n':
  221.       return FALSE;
  222.     /* otherwise, ask again */
  223.     }
  224.   }
  225. }
  226.  
  227.  
  228. /*
  229.  * Save current switch values here --- necessary for multiple input files!
  230.  */
  231.  
  232. static boolean b_smooth;    /* -b */
  233. static boolean gray_scale;    /* -g */
  234. static int num_colors;        /* -q, or 0 if not seen */
  235. static boolean two_pass_q;    /* not -1 */
  236. static boolean do_dither;    /* not -D */
  237. static long cur_mem;        /* -m */
  238. static int cur_trace;        /* -d */
  239.  
  240. #define MAX_FNAME_LEN 150
  241.  
  242.  
  243. /*
  244.  * Process a single input file
  245.  */
  246.  
  247. LOCAL void
  248. process_one_file (char * infilename)
  249. {
  250.   struct decompress_info_struct cinfo;
  251.   struct decompress_methods_struct dc_methods;
  252.   struct external_methods_struct e_methods;
  253.   char outfilename[MAX_FNAME_LEN];
  254.   int i;
  255.  
  256.   /* Select the input and output files */
  257.  
  258.   if ((cinfo.input_file = fopen(infilename, READ_BINARY)) == NULL) {
  259.     fprintf(stderr, "djpeg: can't open %s\n", infilename);
  260.     return;
  261.   }
  262.   /* Make outfilename be infilename with appropriate extension */
  263.   strcpy(outfilename, infilename);
  264.   for (i = strlen(outfilename)-1; i >= 0; i--) {
  265.     switch (outfilename[i]) {
  266.     case ':':
  267.     case '/':
  268.     case '\\':
  269.       i = 0;            /* stop scanning */
  270.       break;
  271.     case '.':
  272.       outfilename[i] = '\0';    /* lop off existing extension */
  273.       i = 0;            /* stop scanning */
  274.       break;
  275.     default:
  276.       break;            /* keep scanning */
  277.     }
  278.   }
  279.   switch (requested_fmt) {
  280.   case FMT_GIF:
  281.     strcat(outfilename, ".GIF");
  282.     break;
  283.   case FMT_PPM:
  284.     strcat(outfilename, ".PPM");
  285.     break;
  286.   case FMT_RLE:
  287.     strcat(outfilename, ".RLE");
  288.     break;
  289.   case FMT_TARGA:
  290.     strcat(outfilename, ".TGA");
  291.     break;
  292.   }
  293.  
  294.   if (! is_write_ok(outfilename)) {
  295.     fclose(cinfo.input_file);
  296.     return;
  297.   }
  298.   if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
  299.     fprintf(stderr, "djpeg: can't create %s\n", outfilename);
  300.     fclose(cinfo.input_file);
  301.     return;
  302.   }
  303.  
  304.   /* Initialize the system-dependent method pointers. */
  305.   cinfo.methods = &dc_methods;
  306.   cinfo.emethods = &e_methods;
  307.   jselerror(&e_methods);    /* error/trace message routines */
  308.   jselmemmgr(&e_methods);    /* memory allocation routines */
  309.   dc_methods.d_ui_method_selection = d_ui_method_selection;
  310.  
  311.   /* Now OK to enable signal catcher. */
  312.   emethods = &e_methods;
  313.  
  314.   /* Set up JPEG parameters. */
  315.   j_d_defaults(&cinfo, TRUE);
  316.   cinfo.do_block_smoothing = b_smooth;
  317.   if (gray_scale)
  318.     cinfo.out_color_space = CS_GRAYSCALE;
  319.   if (num_colors > 0) {
  320.     cinfo.desired_number_of_colors = num_colors;
  321.     cinfo.quantize_colors = TRUE;
  322.   }
  323.   cinfo.two_pass_quantize = two_pass_q;
  324.   cinfo.use_dithering = do_dither;
  325.   e_methods.max_memory_to_use = cur_mem;
  326.   e_methods.trace_level = cur_trace;
  327.  
  328.   /* Start up progress display, unless trace output is on */
  329.   fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename);
  330.   if (cur_trace == 0)
  331.     dc_methods.progress_monitor = progress_monitor;
  332.   
  333.   /* Set up to read a JFIF or baseline-JPEG file. */
  334.   /* A smarter UI would inspect the first few bytes of the input file */
  335.   /* to determine its type. */
  336. #ifdef JFIF_SUPPORTED
  337.   jselrjfif(&cinfo);
  338. #else
  339.   You shoulda defined JFIF_SUPPORTED.   /* deliberate syntax error */
  340. #endif
  341.  
  342.   /* Do it to it! */
  343.   jpeg_decompress(&cinfo);
  344.  
  345.   /* Clear away progress display */
  346.   if (cur_trace == 0)
  347.     fprintf(stderr, "\r                \r");
  348.   fflush(stderr);
  349.  
  350.   /* All done. Close files, disable signal catcher */
  351.   fclose(cinfo.input_file);
  352.   fclose(cinfo.output_file);
  353.   emethods = NULL;
  354. }
  355.  
  356.  
  357. /*
  358.  * Process one filespec; expand wildcards
  359.  */
  360.  
  361. LOCAL void
  362. process_filespec (char * filespec)
  363. {
  364.   FF_DATA ffblock;
  365.   char infilename[MAX_FNAME_LEN];
  366.   int pathlen, i;
  367.   boolean hasext;
  368.  
  369.   /* Determine whether there is a path and an extension */
  370.   pathlen = 0;
  371.   hasext = FALSE;
  372.   for (i = strlen(filespec)-1; i >= 0; i--) {
  373.     switch (filespec[i]) {
  374.     case ':':
  375.     case '/':
  376.     case '\\':
  377.       pathlen = i+1;        /* path part ends here */
  378.       i = 0;            /* stop scanning */
  379.       break;
  380.     case '.':
  381.       hasext = TRUE;        /* there is an extension */
  382.       break;
  383.     default:
  384.       break;            /* keep scanning */
  385.     }
  386.   }
  387.  
  388.   /* Make infilename be filespec; if no explicit extension, attach .JPG */
  389.   strcpy(infilename, filespec);
  390.   if (! hasext)
  391.     strcat(infilename, ".JPG");
  392.  
  393.   /* Scan over matching files */
  394.   if (FINDFIRST(infilename, &ffblock) != 0) {
  395.     fprintf(stderr, "No files matching %s\n", infilename);
  396.   } else {
  397.     do {
  398.       strcpy(infilename, filespec);
  399.       strcpy(infilename + pathlen, ffblock.FF_NAME);
  400.       process_one_file(infilename);
  401.     } while (FINDNEXT(&ffblock) == 0);
  402.   }
  403. }
  404.  
  405.  
  406. /*
  407.  * The main program.
  408.  */
  409.  
  410. GLOBAL int
  411. main (int argc, char **argv)
  412. {
  413.   int c;
  414.  
  415.   /* Set up signal catcher. */
  416.   emethods = NULL;
  417.   signal(SIGINT, signal_catcher);
  418. #ifdef SIGTERM            /* not all systems have SIGTERM */
  419.   signal(SIGTERM, signal_catcher);
  420. #endif
  421.  
  422.   /* Scan command line, process switches */
  423.  
  424.   requested_fmt = DEFAULT_FMT;    /* initialize default switch values */
  425.   b_smooth = FALSE;
  426.   gray_scale = FALSE;
  427.   num_colors = 0;
  428.   two_pass_q = TRUE;
  429.   do_dither = TRUE;
  430.   cur_mem = 300000L;
  431.   cur_trace = 0;
  432.   
  433.   while ((c = egetopt(argc, argv, "GPRTbgq:1Dm:d")) != EOF)
  434.     switch (c) {
  435.     case 'G':            /* GIF output format. */
  436.       requested_fmt = FMT_GIF;
  437.       break;
  438.     case 'P':            /* PPM output format. */
  439.       requested_fmt = FMT_PPM;
  440.       break;
  441.     case 'R':            /* RLE output format. */
  442.       requested_fmt = FMT_RLE;
  443.       break;
  444.     case 'T':            /* Targa output format. */
  445.       requested_fmt = FMT_TARGA;
  446.       break;
  447.     case 'b':            /* Enable cross-block smoothing. */
  448.       b_smooth = TRUE;
  449.       break;
  450.     case 'g':            /* Force grayscale output. */
  451.       gray_scale = TRUE;
  452.       break;
  453.     case 'q':            /* Do color quantization. */
  454.       if (optarg == NULL)
  455.     usage();
  456.       if (sscanf(optarg, "%d", &num_colors) != 1)
  457.     usage();
  458.       break;
  459.     case '1':            /* Use fast one-pass quantization. */
  460.       two_pass_q = FALSE;
  461.       break;
  462.     case 'D':            /* Suppress dithering in color quantization. */
  463.       do_dither = FALSE;
  464.       break;
  465.     case 'm':            /* Maximum memory in Kb (or Mb with 'm'). */
  466.       { long lval;
  467.     char ch = 'x';
  468.  
  469.     if (optarg == NULL)
  470.       usage();
  471.     if (sscanf(optarg, "%ld%c", &lval, &ch) < 1)
  472.       usage();
  473.     if (ch == 'm' || ch == 'M')
  474.       lval *= 1000L;
  475.     cur_mem = lval * 1000L;
  476.       }
  477.       break;
  478.     case 'd':            /* Debugging. */
  479.       /* On first -d, print version identification */
  480.       if (cur_trace == 0)
  481.     fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
  482.         JVERSION, JCOPYRIGHT);
  483.       cur_trace++;
  484.       break;
  485.     case '?':
  486.     default:
  487.       usage();
  488.       break;
  489.     }
  490.  
  491.   /* Process file specifications */
  492.   if (optind >= argc)
  493.     usage();            /* no filespecs?? */
  494.  
  495.   while (optind < argc)
  496.     process_filespec(argv[optind++]);
  497.  
  498.   /* All done. */
  499.   exit(EXIT_SUCCESS);
  500.   return 0;            /* suppress no-return-value warnings */
  501. }
  502.